﻿using System;
using System.Collections.Concurrent;
using System.Runtime.CompilerServices;

namespace JH
{
    /// <summary>
    ///  用来支持 await 关键字，泛型版本
    /// </summary>
    public struct JTaskMethodBuilder<T>
    {
        private BuildInfo _info;

        /// <summary>
        /// 必需的静态 Create 方法
        /// </summary>
        public static JTaskMethodBuilder<T> Create()
        {
            var ret = new JTaskMethodBuilder<T>
            {
                _info = BuildInfo.Rent()
            };
            ret.Task = new JTask<T>(() => ret._info.HasResultValue, () => ret._info.Result);
            return ret;
        }

        /// <summary>
        /// 获取任务
        /// </summary>
        public JTask<T> Task { get; private set; }

        /// <summary>
        /// 开始
        /// </summary>
        public void Start<TStateMachine>(ref TStateMachine stateMachine)
            where TStateMachine : IAsyncStateMachine
        {
            stateMachine.MoveNext();
        }

        /// <summary>
        /// 设置结果
        /// </summary>
        public void SetResult(T result)
        {
            _info.Result = result;
            _info.HasResultValue = true;
            _info.Return();
        }

        /// <summary>
        /// 设置异常
        /// </summary>
        public void SetException(Exception exception)
        {
            Task.GetAwaiter().SetException(exception);
            _info.Return();
        }

        /// <summary>
        /// 设置StateMachine
        /// </summary>
        public void SetStateMachine(IAsyncStateMachine stateMachine)
        {
        }

        /// <summary>
        /// await 完成时调用
        /// </summary>
        public void AwaitOnCompleted<TAwaiter, TStateMachine>(
            ref TAwaiter awaiter, ref TStateMachine stateMachine)
            where TAwaiter : INotifyCompletion
            where TStateMachine : IAsyncStateMachine
        {
            awaiter.OnCompleted(stateMachine.MoveNext);
        }

        /// <summary>
        /// UnsafeAwait 完成时调用
        /// </summary>
        public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(
            ref TAwaiter awaiter, ref TStateMachine stateMachine)
            where TAwaiter : ICriticalNotifyCompletion
            where TStateMachine : IAsyncStateMachine
        {
            awaiter.UnsafeOnCompleted(stateMachine.MoveNext);
        }

        /// <summary>
        ///  用于解决值类型的状态变化问题
        /// </summary>
        private sealed class BuildInfo
        {
            public T Result;
            public bool HasResultValue;
            private static readonly ConcurrentQueue<BuildInfo> Pool = new();

            public static BuildInfo Rent()
            {
                var ret = Pool.TryDequeue(out var poolGet) ? poolGet : new BuildInfo();
                ret.HasResultValue = false;
                ret.Result = default;
                return ret;
            }

            public void Return()
            {
                Pool.Enqueue(this);
            }
        }
    }
}